#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdint.h>

#define DEV_UART 			"/dev/ttyUSB0"
int dev_uart_fd;            //串口设备描述符

struct env_info
{
	uint8_t head[3];	    //标识位st:
	uint8_t type;		    //数据类型
	uint8_t snum;		    //仓库编号
	uint8_t temp[2];	    //温度	
	uint8_t hum[2];		    //湿度
	uint8_t x;			    //三轴信息
    uint8_t y;
    uint8_t z;
	uint32_t ill;		    //光照
	uint32_t bet;           //电池电量
	uint32_t adc;           //电位器信息
};

struct conver_env_info {
    int snum;               //仓库编号
    float temperature;      //温度
    float humidity;         //湿度
    float ill;              //光照
    float bet;              //电池电量
    float adc;              //电位器信息
    
    signed char x;          //三轴信息
    signed char y;			 
    signed char z;			 
};

static float dota_atof (char unitl)
{
    if (unitl > 100)
    {
        return unitl / 1000.0;
    }
    else if (unitl > 10)
    {
        return unitl / 100.0;
    }
    else
    {
        return unitl / 10.0;
    }
}

void serial_init(int fd)
{
    struct termios options;
    tcgetattr(fd, &options);
    options.c_cflag |= ( CLOCAL | CREAD );
    options.c_cflag &= ~CSIZE;
    options.c_cflag &= ~CRTSCTS;
    options.c_cflag |= CS8;
    options.c_cflag &= ~CSTOPB;
    options.c_iflag |= IGNPAR;
    options.c_iflag &= ~(ICRNL | IXON);
    options.c_oflag = 0;
    options.c_lflag = 0;

    cfsetispeed(&options, B115200);
    cfsetospeed(&options, B115200);
    tcsetattr(fd,TCSANOW,&options);
}

static float dota_adc (unsigned int ratio)
{
    return ((ratio * 3.3) / 1024);
}

int UART_Init()
{
    if ((dev_uart_fd = open (DEV_UART, O_RDWR)) < 0)
    {
        perror ("open uart err");
        return -1;
    }
    printf("Open UART success\n");
	serial_init(dev_uart_fd);
    return 0;
}

int main(int argc,const char *argv[])
{
	int server_fd,client_fd;                            //定义两个套接字描述符，用于描述服务器和客户端套接字
	pid_t pid;                                          //定义变量pid用于区分父子进程
	int ret;                                            //一些接口函数返回值，用于判断接口函数是否执行成功
	char buf[64] = "";                                  //收发数据缓冲区，由于父子进程内存空间独立，故可使用同一个缓冲区
	struct sockaddr_in server_addr,client_addr;         //用于描述服务器和客户端的网络信息结构体
	socklen_t addrlen = sizeof(struct sockaddr_in);     //描述网络信息结构体变量大小的变量

    struct env_info envinfo;
	struct conver_env_info env_msg;

    if(UART_Init() == -1){
        perror("UART init Fail");
        return -1;
    }

	//1、相当于买了个手机
	//@AF_INET：协议族
	//@SOCK_STREAM：流式套接字，专用于tcp通信
	//返回值：服务器套接字描述符
	server_fd = socket(AF_INET, SOCK_STREAM, 0);
	if(server_fd == -1)
	{
		perror("fail to socket");
		return -1;
	}
	//2、相当于办了张手机卡
	memset(&server_addr,0,sizeof(server_addr));         //清空这张手机卡
	//填写协议族，端口号，ip地址，注意大小端转换
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(atoi(argv[2]));
	server_addr.sin_addr.s_addr = inet_addr(argv[1]);

	//3、相当于插卡
	//@server_fd：服务器套接字描述符
	//@server_addr：服务器网络信息结构体，注意强制类型转化
	//@server_addr:网络信息结构体的大小
	ret = bind(server_fd, (struct sockaddr *)&server_addr,sizeof(server_addr));
	if(ret == -1)
	{
		perror("fail to bind");
		return -1;
	}
	//4、相当于开机
	//开机监听套接字
	//第一个参数为服务器套接字描述符，第二个参数为监听队列长度，最大为5
	ret = listen(server_fd, 5);
	if(ret == -1)
	{
		perror("fail to listen");
		return -1;
	}
	//5、相当于接电话
	//主要目的是获取描述客户端的套接字描述符，通过操作客户端套接字描述符，
	//可完成相应的收发功能
	//@server_fd：服务器套接字描述符
	//@client_addr：用于存储客户端的网络信息
	//@addrlen:客户端网络信息结构体的长度，注意传地址
	client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &addrlen);
	if(client_fd == -1)
	{
		perror("fail to accept");
		return -1;
	}
	printf("client addr:%s\n",inet_ntoa(client_addr.sin_addr));     //打印一下客户端的网络信息
	pid = fork();       //通过fork函数创建子进程
	//当fork返回值pid大于0时，为父进程
	if(pid > 0)
	{
		//父进程内进行tcp的接收工作
		while(1)
		{
			//6、通话，此处为听
			//通过recv函数接收客户端数据
			//@client_fd:客户端套接字描述符
			//@buf：用于接收客户端数据的数组
			//@64：尝试接收64字节
			//@0:阻塞接收
			ret = recv(client_fd, &env_msg, sizeof(struct conver_env_info), 0);
			//ret大于0代表收到了数据
			if(ret > 0)
			{
                printf("Recive Success\n");
                write(dev_uart_fd,&env_msg,sizeof(struct conver_env_info));
                printf("UART send success\n");
			}
			//ret小于0代表接收出错
			else if(ret < 0)
			{
				perror("fail to recv\n");
				close(client_fd);
				close(server_fd);
				return -1;
			}
			//ret等于0代表对端退出
			else
			{
				printf("peer exit\n");
				close(client_fd);
				close(server_fd);
				return 0;
			}
		}
	}
	//pid等于0代表子进程
	else if(pid == 0)
	{
		//子进程主要完成tcp的发送工作
		while(1)
		{
			// scanf("%s",buf);
			// getchar();
			// //6、通话，此处为说
			// //通过send函数完成tcp的发送功能
			// //@client_fd:客户端套接字描述符
			// //@buf:存放将要发送的数据的数组
			// //@strlen(buf)：要发送的数据的长度
			// //@0:阻塞发送
			// send(client_fd, buf, strlen(buf), 0);
			// memset(buf,0,64);
            ret = read(dev_uart_fd, &envinfo, sizeof(struct env_info));     //从串口读取数据
            // printf("UART Read success\n");
            if(ret != sizeof(envinfo)){
                printf("fail to read\n");
                continue;
            }
            
            //结构体数据转换
            env_msg.x = envinfo.x;
            env_msg.y = envinfo.y;
            env_msg.z = envinfo.z;
            env_msg.temperature = envinfo.temp[0] + dota_atof(envinfo.temp[1]);
            env_msg.humidity = envinfo.hum[0] + dota_atof(envinfo.hum[1]);
            env_msg.ill = envinfo.ill;
            env_msg.bet = dota_adc(envinfo.bet);
            env_msg.adc = dota_adc(envinfo.adc);
            sleep(1);

            //终端显示数据
            printf("x:%c y:%c z:%c temp:%.2f hum:%.2f ill:%.2f bet:%.2f adc:%.2f\n",env_msg.x,env_msg.y,env_msg.z,env_msg.temperature,env_msg.humidity,env_msg.ill,env_msg.bet,env_msg.adc);
            
            //开始发送转换后的结构体数据
            send(client_fd, &env_msg, sizeof(struct conver_env_info), 0);
            memset(&envinfo,0,sizeof(struct conver_env_info));
		}
	}
	else
	{
		printf("err\n");
		return -1;
	}
	return 0;
}